import requests
import json
import os
import re
from urllib.parse import urlunparse, urlencode, urlunsplit
from tqdm import tqdm
from concurrent.futures import ThreadPoolExecutor

def douyin(url, path, max_cursor = 0):
    url = url.split('?')[0]
    sec_user_id = url.split('user/')[1]

    headers = {
        'User-Agent': "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36",
        "referer": "https://www.douyin.com/follow",
        "cookie": "ttwid=1%7CPUeGNvzrVKtX88bQme6pnKSONQ-khOLwyz8T5bewKkI%7C1734315604%7Cfa0fb147bcf84ca184f5dadf39915dc8eaf077cb1dc05012174668ea5e47ec13; UIFID_TEMP=6a8253199192b669ecb5c608c1e1200542a2d66d943f26f79f1de78af50d7a1a1434c6e6467ba1da04357586f5269eedaa855e2d0abe45c80156cd2d68f048b5b09306236187b15d0e49a275da66e9c7bd8065ba7e1d0f52eec107dfa36c44fec5f229f35e958b09055e99dba75e28aa; passport_csrf_token=66fbc15bfe46df76afcd7aafd35df284; passport_csrf_token_default=66fbc15bfe46df76afcd7aafd35df284; s_v_web_id=verify_m4qeqgcu_9SgvTgS6_7wKp_40Zv_8dAT_UZlWvy2oBvwP; fpk1=U2FsdGVkX19PV6tDXdw1qmnnG5Pd6Wgm2Nn61tQhPv9aoArSC0P9OQpmL6pcvXT2xLaBSQtmD42C9efboVLzLw==; fpk2=1062ce83a454d50e5d2c2a73c86fb978; bd_ticket_guard_client_web_domain=2; UIFID=6a8253199192b669ecb5c608c1e1200542a2d66d943f26f79f1de78af50d7a1af567a4cf8e1f6b13bcd036c85961921249b9c471bc443767989c448e03da5e4cdd1dac784abce520e794a910616354b3010efce5dd4015c13f24119d0a97b1ca2db39269dc8be8897b7665c875f886c27985d028c764d081f7559a38313d7b6de0ec54df7c3190c85d05524773291f36d27ed20a1caa64e71310df7dca55d123ffaa8db6790b4ed02246b4689877cc7d1992478655b7e3734768b7f7327a6359; csrf_session_id=7d90fa6e56de522a5d312628fb7f915a; is_dash_user=0; FORCE_LOGIN=%7B%22videoConsumedRemainSeconds%22%3A180%7D; douyin.com; device_web_cpu_core=20; device_web_memory_size=8; architecture=amd64; strategyABtestKey=%221735095682.139%22; xgplayer_user_id=307088608944; biz_trace_id=48557825; passport_assist_user=CjwmRr6N49gHu-nU6ObBnZIp-xWIEoGJ732qCjYU_r-Dsx-AVJk5rtwOcLGp8vHuQOVoLgBaViCXaOX0NHUaSgo8QYpYc50HAlGRvSRlo-kVfMA8xVbtHoNIuAKHG7-PnzjrI1Ju9iGpND9YOzP9UNp1p1AwRrVy_f9c1riOEIaD5Q0Yia_WVCABIgEDN-dc_Q%3D%3D; n_mh=fVxob8ND8TOXRilj4PG2vsaiiwxV0wxH4pB_fsDOkIc; sso_uid_tt=e5d6a57d8b65b0bbc4bfc3cbf8065a94; sso_uid_tt_ss=e5d6a57d8b65b0bbc4bfc3cbf8065a94; toutiao_sso_user=2f46d0cb9f9b6fc5b1405d375181d788; toutiao_sso_user_ss=2f46d0cb9f9b6fc5b1405d375181d788; sid_ucp_sso_v1=1.0.0-KGRjNGEwN2I1MDU2Y2JhMGRkMDRhM2Q5YzI5MTcxMWI1NmQwNzk0ZGYKHwiW0LXhvgIQ4uutuwYY7zEgDDDD19_SBTgGQPQHSAYaAmxxIiAyZjQ2ZDBjYjlmOWI2ZmM1YjE0MDVkMzc1MTgxZDc4OA; ssid_ucp_sso_v1=1.0.0-KGRjNGEwN2I1MDU2Y2JhMGRkMDRhM2Q5YzI5MTcxMWI1NmQwNzk0ZGYKHwiW0LXhvgIQ4uutuwYY7zEgDDDD19_SBTgGQPQHSAYaAmxxIiAyZjQ2ZDBjYjlmOWI2ZmM1YjE0MDVkMzc1MTgxZDc4OA; login_time=1735095778300; passport_auth_status=33ba79d6addd261b45c5d6c2e7b4cddc%2C; passport_auth_status_ss=33ba79d6addd261b45c5d6c2e7b4cddc%2C; uid_tt=1707cd063f681966207aa8d8a7224bab; uid_tt_ss=1707cd063f681966207aa8d8a7224bab; sid_tt=f07150bef1b26c277fe24574be92e8c2; sessionid=f07150bef1b26c277fe24574be92e8c2; sessionid_ss=f07150bef1b26c277fe24574be92e8c2; is_staff_user=false; __ac_nonce=0676b75e300b59ea039d9; publish_badge_show_info=%220%2C0%2C0%2C1735095779391%22; SelfTabRedDotControl=%5B%5D; _bd_ticket_crypt_doamin=2; _bd_ticket_crypt_cookie=4b12f61e80fdc7c6d0f0796e8279683b; __security_server_data_status=1; sid_guard=f07150bef1b26c277fe24574be92e8c2%7C1735095783%7C5183998%7CSun%2C+23-Feb-2025+03%3A03%3A01+GMT; sid_ucp_v1=1.0.0-KGQ5Mjc5NWUyNGY4M2E3NDI2ZmZjYmZlNzRhZWVkNmM1YzllY2QzNTMKGQiW0LXhvgIQ5-utuwYY7zEgDDgGQPQHSAQaAmxmIiBmMDcxNTBiZWYxYjI2YzI3N2ZlMjQ1NzRiZTkyZThjMg; ssid_ucp_v1=1.0.0-KGQ5Mjc5NWUyNGY4M2E3NDI2ZmZjYmZlNzRhZWVkNmM1YzllY2QzNTMKGQiW0LXhvgIQ5-utuwYY7zEgDDgGQPQHSAQaAmxmIiBmMDcxNTBiZWYxYjI2YzI3N2ZlMjQ1NzRiZTkyZThjMg; stream_player_status_params=%22%7B%5C%22is_auto_play%5C%22%3A0%2C%5C%22is_full_screen%5C%22%3A0%2C%5C%22is_full_webscreen%5C%22%3A0%2C%5C%22is_mute%5C%22%3A0%2C%5C%22is_speed%5C%22%3A1%2C%5C%22is_visible%5C%22%3A1%7D%22; xg_device_score=7.983585126412278; dy_swidth=1920; dy_sheight=1080; stream_recommend_feed_params=%22%7B%5C%22cookie_enabled%5C%22%3Atrue%2C%5C%22screen_width%5C%22%3A1920%2C%5C%22screen_height%5C%22%3A1080%2C%5C%22browser_online%5C%22%3Atrue%2C%5C%22cpu_core_num%5C%22%3A20%2C%5C%22device_memory%5C%22%3A8%2C%5C%22downlink%5C%22%3A10%2C%5C%22effective_type%5C%22%3A%5C%224g%5C%22%2C%5C%22round_trip_time%5C%22%3A50%7D%22; bd_ticket_guard_client_data=eyJiZC10aWNrZXQtZ3VhcmQtdmVyc2lvbiI6MiwiYmQtdGlja2V0LWd1YXJkLWl0ZXJhdGlvbi12ZXJzaW9uIjoxLCJiZC10aWNrZXQtZ3VhcmQtcmVlLXB1YmxpYy1rZXkiOiJCS1BRWkJWYjVWYW9oTjNEeG9JV0diTDNwOWpUMENrTWE2OGRWc2VITHpiNEZpRWpjMENldmUzU1d5V2FVNGI0cUdMQ0NJYzRUSUpCMVl3dlpXRVgwMWc9IiwiYmQtdGlja2V0LWd1YXJkLXdlYi12ZXJzaW9uIjoyfQ%3D%3D; passport_fe_beating_status=true; volume_info=%7B%22isUserMute%22%3Atrue%2C%22isMute%22%3Atrue%2C%22volume%22%3A0.6%7D; home_can_add_dy_2_desktop=%221%22; IsDouyinActive=true; odin_tt=5b33d0533bed3a318de967281a5f6f5eb0d6fd688a4d945d48c2b5b6bd726a672db7c4b7f19af452b37282329735036a; download_guide=%222%2F20241225%2F0%22",
    }
    #sec_user_id = 'MS4wLjABAAAASltvIi9iixS80NFLsaOBHPbur0ntRPpVkproC-EeqtN3X_9BozWVbV_N7F2XFrXj'
    base_url = 'https://www.douyin.com/aweme/v1/web/aweme/post/'
    params = {
        'device_platform': 'webapp',
        'aid': '6383',
        'channel': 'channel_pc_web',
        'sec_user_id': sec_user_id,
        'max_cursor': max_cursor,
        'locate_item_id': 7261906079322213632,
        'locate_query': 'false',
        'show_live_replay_strategy': 1,
        'need_time_list': 1,
        'time_list_query': 0,
        'whale_cut_token': '',
        'cut_version': 1,
        'count': 18,
        'publish_video_strategy_type': 2,
        'from_user_page': 1,
        'update_version_code': 170400,
        'pc_client_type': 1,
        'pc_libra_divert': 'Windows',
        'version_code': 290100,
        'version_name': '29.1.0',
        'cookie_enabled': 'true',
        'screen_width': '1920',
        'screen_height': '1080',
        'browser_language': 'zh-CN',
        'browser_platform': 'Win32',
        'browser_name': 'Chrome',
        'browser_version': '86.0.4240.198v',
        'browser_online': 'true',
        'engine_name': 'Blink',
        'engine_version': '86.0.4240.198',
        'os_name': 'Windows',
        'os_version': 10,
        'cpu_core_num': 20,
        'device_memory': 8,
        'platform': 'PC',
        'downlink': 10,
        'effective_type': '4g',
        'round_trip_time': 0,
        'webid': '7448828719651882505',
        'uifid': '6a8253199192b669ecb5c608c1e1200542a2d66d943f26f79f1de78af50d7a1af567a4cf8e1f6b13bcd036c85961921249b9c471bc443767989c448e03da5e4cdd1dac784abce520e794a910616354b3010efce5dd4015c13f24119d0a97b1ca2db39269dc8be8897b7665c875f886c27985d028c764d081f7559a38313d7b6de0ec54df7c3190c85d05524773291f36d27ed20a1caa64e71310df7dca55d123ffaa8db6790b4ed02246b4689877cc7d1992478655b7e3734768b7f7327a6359',
        'verifyFp': 'verify_m4qeqgcu_9SgvTgS6_7wKp_40Zv_8dAT_UZlWvy2oBvwP',
        'fp': 'verify_m4qeqgcu_9SgvTgS6_7wKp_40Zv_8dAT_UZlWvy2oBvwP',
        'msToken': 'qPwruIZnG5ZWeQL3ZwesTh7Eh6ZSj4dg3Mfp9A8mfBYWgKwrOymJ1AvEQDKf9Oys6kYuD5Jgp-n9k2qCCyhlwAdKVXA5qRrUJKCZ384PDWnvzZzLlSmg9-_QmvEJ-aEtZJOHsHaF-DOnDwHESis3vHq1CVFuuy6N-z7SLpJiOQBXaVzOUdEviw==',
        'a_bogus': 'mvsfhqXido85cVFt8OnnHAcla9dANTWyPNixWEMT7xFdGZMYnuPBinCCroL2-sDNWWpwwq175ntAbDnc/4XTZ9nkumpDSwwbc4V9IX6L2qi4G0vQDNgwSLsFowBNU5Tql/Vvi1DI0Ut9gjdAiqQu/d5r9/KeQ58BMZOWk/zcT9s6Z06ALZn3PBGkNXJqvf==',
    }
    query_string = urlencode(params)
    full_url = f"{base_url}?{query_string}"

    res = requests.get(url=full_url, headers=headers)
    aweme_list = res.json().get("aweme_list")
    has_more = res.json().get("has_more")
    max_cursor_next = res.json().get("max_cursor")
    print('has_more', has_more)
    print('下一页', max_cursor_next)
    with ThreadPoolExecutor(20) as pool:
        for aweme in tqdm(aweme_list):
            pool.submit(dinYinDownload, aweme, path)

    print(len(aweme_list), "个视频已下载完成")
def dinYinDownload(aweme, path):
    nickname = aweme.get("author").get("nickname")
    nickname = filter_special_characters(nickname)

    create_time = aweme.get("create_time")
    media_type = aweme.get("media_type")

    title = aweme.get("desc")
    titles = filter_special_characters(title)
    if titles == '':
        titles = create_time


    folder_path = f"{path}/douyin/{nickname}" #生成的地址
    # 检查文件夹是否存在
    if not os.path.exists(folder_path):
        os.makedirs(folder_path)

    if media_type == 2:
        folder_img_path = f"{path}/douyin/{nickname}/{titles}"
        # 检查文件夹是否存在
        if not os.path.exists(folder_img_path):
            os.makedirs(folder_img_path)
        img_list = aweme.get("images")
        for i, img in enumerate(img_list):
            urls = img['url_list'][-1] #得到图片url
            file = f"{folder_path}/{titles}/{i}.jpeg"
            downloadVideoImg(urls, file, titles)

    if media_type == 4:
        #视频下载
        urls = aweme.get("video").get("play_addr").get("url_list")[-1]
        file = f"{folder_path}/{titles}.mp4"
        downloadVideoImg(urls, file, titles)


def downloadVideoImg(urls, file, titles):
    # 如果存在就不下载了
    if os.path.exists(file):
        print("已存在，不需要下载", titles)
        return file
    res = requests.get(urls)
    with open(file, 'wb') as f:
        f.write(res.content)
        print(titles, "下载成功！", titles)

def filter_special_characters(text):
    pattern = re.compile('[^\\w\\s]')
    filtered_text = re.sub(pattern, '', text)
    filtered_texts = filtered_text.replace(" ", "-").replace("\n", "")  # 去掉空格换行
    return filtered_texts


if __name__ == '__main__':
    url= 'https://www.douyin.com/user/MS4wLjABAAAASltvIi9iixS80NFLsaOBHPbur0ntRPpVkproC-EeqtN3X_9BozWVbV_N7F2XFrXj?from_tab_name=main&vid=7261906079322213632'
    path = '1'
    douyin(url, path)